﻿using System;
using System.Collections.Generic;
using System.Linq;
using BigData.DataContracts.Objects.BigData;
using BigDataFramework.Library.Helpers;
using BigDataFramework.Repositories;
using Igloo.SharpSquare.Entities;
using MongoDB.Bson;
using BigData.DataContracts.Objects.FourSquare;

namespace BigDataFramework.Library.Objects.DataAdapters.FourSquare
{
    public class FourSquareDataAdapterCheckin : FourSquareDataAdapterBase<BigDataFourSquareCheckin>
    {
        protected override List<BigDataFourSquareCheckin> RetrieveDataFromAPIForUser(BigDataUser user, DateTime startDate, DateTime endDate)
        {
            DateTime unixEpochBeginning = DateTime.Parse("1/1/1970").ToUniversalTime();
            string fourSquareUserId = "self"; // For now only self is supported // TODO: Convert User Identifier to valid access token and user id
            string accessToken = "XI5OH05FZ3WZZY55ROQ3P0DZHLMMNEA5L0C5GBSTNFLO1FXR"; // TODO: Pull access token from database

            if (string.IsNullOrEmpty(accessToken))
                throw new Exception(string.Format("Unable to retrieve valid auth token for BigDataUserIdentifier [{0}] from the database", user._id.ToString()));

            // Set the access token
            this._Client.SetAccessToken(accessToken);

            // Generate the parameters to pass in
            Dictionary<string, string> parameters = new Dictionary<string, string>();
            //parameters.Add("USER_ID", "self");    // For now, only self is supported
            parameters.Add("limit", "250");         // Number of results to return, up to 250.
            //parameters.Add("offset", "self");     // The number of results to skip. Used to page through results.
            parameters.Add("sort", "oldestfirst");  // How to sort the returned checkins. Can be newestfirst or oldestfirst.

            // If the date time is min or something similar, change it to the beginning of the epoch as foursquare does not like negative numbers
            if (startDate >= unixEpochBeginning)
                parameters.Add("afterTimestamp", DateTimeHelper.ToUnixTimeStamp(startDate.ToUniversalTime()).ToString()); // Retrieve the first results to follow these seconds since epoch. This should be useful for paging forward in time, or when polling for changes. To avoid missing results when polling, we recommend subtracting several seconds from the last poll time and then de-duplicating.
            else
                parameters.Add("afterTimestamp", DateTimeHelper.ToUnixTimeStamp(unixEpochBeginning).ToString());

            // If the date time is min or something similar, change it to the beginning of the epoch as foursquare does not like negative numbers
            if (endDate >= unixEpochBeginning)
                parameters.Add("beforeTimestamp", DateTimeHelper.ToUnixTimeStamp(endDate.ToUniversalTime()).ToString()); // Retrieve the first results prior to these seconds since epoch. Useful for paging backward in time.
            else
                parameters.Add("beforeTimestamp", DateTimeHelper.ToUnixTimeStamp(unixEpochBeginning).ToString());

            // Retrieve User's check ins
            return this._Client.GetUserCheckins(fourSquareUserId, parameters).Select<Checkin, BigDataFourSquareCheckin>(c =>

                    new BigDataFourSquareCheckin()
                    {
                        AssociatedUserIds = new List<string>() { user._id },
                        FourSquareCheckin = c
                    }

                ).ToList();
        }

        public override Event ConvertObjToEvent(BigDataFourSquareCheckin obj)
        {
            Photo photo;

            DateTime recordCreateDate = DateTimeHelper.FromUnixTimeStamp(long.Parse(obj.FourSquareCheckin.createdAt));

            // Create an event from the BigDataFourSquareCheckin details
            Event output = new Event()
            {
                AffiliatedUserIds = obj.AssociatedUserIds.Select<string, ObjectId>(uid => ObjectId.Parse(uid)).ToList(),

                Headline = string.Format("FourSquare checkin at {0}", obj.FourSquareCheckin.venue.name),
                Text = obj.FourSquareCheckin.shout,
                StartDate = recordCreateDate,
                EndDate = recordCreateDate,

                RegisteredCollectionId = this.RegisteredCollectionId,
                RegisteredCollectionObjectId = ObjectId.Parse(obj._id),

                RecordStartDate = DateTime.Now,
                RecordEndDate = DateTime.MaxValue
            };

            // Is there anything which we could pass off as media?
            if (    obj.FourSquareCheckin.venue == null
                ||  obj.FourSquareCheckin.venue.photos == null
                ||  obj.FourSquareCheckin.venue.photos.groups == null
                ||  obj.FourSquareCheckin.venue.photos.groups[0].items == null
                ||  obj.FourSquareCheckin.venue.photos.groups[0].items.Count <= 0)
                return output; // No, return what we have

            // Yes, pull the first "photo" object
            photo = obj.FourSquareCheckin.venue.photos.groups[0].items[0];

            // Create and associate a media object which contains the photo's details
            output.Media = new BigData.DataContracts.Objects.BigData.EventMedia()
            {
                URL = photo.url,
                Credit = string.Format("{0} - {1}", photo.source.name, photo.source.url),
                Caption = obj.FourSquareCheckin.shout
            };

            return output;
        }
    }
}